package cn.fintecher.pangolin.service.business.service;

import cn.fintecher.pangolin.common.enums.*;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.DepartmentModel;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.IdcardUtils;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.*;
import cn.fintecher.pangolin.entity.mysql.*;
import cn.fintecher.pangolin.service.business.model.AppCardModel;
import cn.fintecher.pangolin.service.business.model.request.AppAddFollowRecordRequest;
import cn.fintecher.pangolin.service.business.model.request.FindAppCaseRequest;
import cn.fintecher.pangolin.service.business.model.response.*;
import cn.fintecher.pangolin.service.business.repository.elasticsearch.*;
import cn.fintecher.pangolin.service.business.repository.jparepository.AssistCaseRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.CaseInfoRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.PaymentCheckRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.UserRepository;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Type;
import java.util.*;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 10:44 2019/11/14
 */

@Service("appMainService")
@Transactional(rollbackFor = Exception.class)
public class AppMainService {
    @Autowired
    private BaseService baseService;

    @Autowired
    private AssistCaseRepository assistCaseRepository;

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private BaseCaseRespository baseCaseRespository;

    @Autowired
    private PersonalContactElastic personalContactElastic;

    @Autowired
    private PersonalAddressElastic personalAddressElastic;

    @Autowired
    private PaymentRecordElastic paymentRecordElastic;

    @Autowired
    private CaseFollowRecordElastic caseFollowRecordElastic;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PaymentCheckRepository paymentCheckRepository;

    @Autowired
    private CaseInfoRepository caseInfoRepository;

    /**
     * app案件列表查询
     */
    public Page<FindAppCaseResponse> getAllCase(FindAppCaseRequest request, Pageable pageable, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        if (userModel.getIsManage().equals(BaseSelect.YES)) {
            request.setCode(departmentModel.getDepartCode());
        } else {
            request.setUserId(userModel.getId());
        }
        BooleanBuilder builder = request.getBuilder();
        Page<AssistCase> page = assistCaseRepository.findAll(builder, pageable);
        Page<FindAppCaseResponse> result = page.map(e -> modelMapper.map(e, FindAppCaseResponse.class));
        List<FindAppCaseResponse> list = result.getContent();
        list.forEach(e -> {
            if (StringUtils.isNotBlank(e.getCertificateNo())) {
                e.setAge(IdcardUtils.getAgeByIdCard(e.getCertificateNo()));
            }
            String dateStr = ZWDateUtil.fomratterDate(e.getVisitTimeEnd(), "yyyy-MM-dd");
            if (dateStr.equals(ZWDateUtil.fomratterDate(new Date(), "yyyy-MM-dd"))) {
                e.setFlag(1);
            } else {
                Period p = new Period(new DateTime(ZWDateUtil.getNowDate()), new DateTime(dateStr), PeriodType.days());
                if (p.getDays() <= 3 && p.getDays() >= 0) {
                    e.setFlag(2);
                }
            }
        });
        return result;
    }

    /**
     * app外访案件列表查询
     */
    public Page<FindAppCaseResponse> getAllOutCase(FindAppCaseRequest request, Pageable pageable, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        if (userModel.getIsManage().equals(BaseSelect.YES)) {
            request.setCode(departmentModel.getDepartCode());
        } else {
            request.setUserId(userModel.getId());
        }
        BooleanBuilder builder = request.getCaseBuilder();
        Page<CaseInfo> page = caseInfoRepository.findAll(builder, pageable);
        return page.map(e -> modelMapper.map(e, FindAppCaseResponse.class));
    }

    /**
     * 获取基础信息
     */
    public AppBaseCaseResponse getBaseInfo(String caseId) {
        BaseCase baseCase = baseCaseRespository.findById(caseId).orElseThrow(() -> new BadRequestException(null, "caseId", "case.is.null"));
        AppBaseCaseResponse response = new AppBaseCaseResponse();
        response.setPhone(baseCase.getPhone());
        response.setCertificateNo(baseCase.getCertificateNo());
        response.setSex(baseCase.getSex());
        response.setPersonalName(baseCase.getPersonalName());
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.matchPhraseQuery("caseId.keyword", caseId));
        //查询联系人信息
        Iterable<PersonalContact> personalContactIterable = personalContactElastic.search(builder);
        List<PersonalContact> personalContacts = IterableUtils.toList(personalContactIterable);
        Type contactType = new TypeToken<List<PersonalContactResponse>>() {
        }.getType();
        List<PersonalContactResponse> contactResponses = modelMapper.map(personalContacts, contactType);
        response.setContacts(contactResponses);
        //查询地址信息
        Iterable<PersonalAddress> personalAddressIterable = personalAddressElastic.search(builder);
        List<PersonalAddress> personalAddresses = IterableUtils.toList(personalAddressIterable);
        Type addressType = new TypeToken<List<PersonalAddressResponse>>() {
        }.getType();
        List<PersonalAddressResponse> addressResponses = modelMapper.map(personalAddresses, addressType);
        response.setAddress(addressResponses);
        return response;
    }

    /**
     * 获取共债信息
     */
    public AppCaseInfoResponse getCaseInfo(String caseId) {
        BaseCase baseCase = baseCaseRespository.findById(caseId).orElseThrow(() -> new BadRequestException(null, "baseCase", "case.is.null"));
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.matchPhraseQuery("certificateNo.keyword", baseCase.getCertificateNo()));
        builder.must(QueryBuilders.matchPhraseQuery("isClear.keyword", BaseSelect.NO.name()));
        Iterable<BaseCase> baseCaseIterable = baseCaseRespository.search(builder);
        List<BaseCase> baseCases = IterableUtils.toList(baseCaseIterable);
        List<BaseCase> list = new ArrayList<>();
        for (BaseCase baseCase1 : baseCases) {
            if (baseCase1.getId().equals(caseId)) {
                list.add(baseCase1);
                baseCases.remove(baseCase1);
                break;
            }
        }
        list.addAll(baseCases);
        Optional<AssistCase> optional = assistCaseRepository.findOne(QAssistCase.assistCase.caseId.eq(caseId));
        AppCaseInfoResponse response = new AppCaseInfoResponse();
        response.setCaseCity(baseCase.getCity());
        response.setHandsNumber(baseCase.getStage());
        response.setPrincipalName(baseCase.getPrincipalName());
        response.setPrincipalId(baseCase.getPrincipalId());
        response.setDelegationDate(baseCase.getDelegationDate());
        response.setEndCaseDate(baseCase.getEndCaseDate());
        optional.ifPresent(assistCase -> response.setVisitTimeEnd(assistCase.getVisitTimeEnd()));
        Type listType = new TypeToken<List<AppCardModel>>() {
        }.getType();
        List<AppCardModel> models = modelMapper.map(list, listType);
        response.setCardInfos(models);
        return response;
    }

    /**
     * 对账单查询
     */
    public List<PaymentRecord> caseBillRecord(String caseId) {
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.matchPhraseQuery("caseId.keyword", caseId)).must(QueryBuilders.matchPhraseQuery("flag", 0));
        Iterable<PaymentRecord> iterable = paymentRecordElastic.search(builder);
        List<PaymentRecord> list = IterableUtils.toList(iterable);
        list.sort((e1, e2) -> e2.getPaymentDate().compareTo(e1.getPaymentDate()));
        return list;
    }

    /**
     * 外访催记
     */
    public Page<CaseFollowupRecord> getFollowRecord(String certificateNo, Pageable pageable) {
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.matchPhraseQuery("certificateNo.keyword", certificateNo));
        builder.must(QueryBuilders.matchPhraseQuery("collectionWay", 1));
        SortBuilder sort = SortBuilders.fieldSort("operateTime").unmappedType("date").order(SortOrder.DESC);
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).withSort(sort).withPageable(pageable).build();
        return caseFollowRecordElastic.search(searchQuery);
    }

    /**
     * 添加催记
     */
    public void saveFollowRecord(AppAddFollowRecordRequest request, String token) {
        Optional<CaseInfo> optional = caseInfoRepository.findById(request.getCaseId());
        if (!optional.isPresent()) {
            throw new BadRequestException(null, "caseInfo", "case.is.done");
        }
        CaseInfo caseInfo = optional.get();
        if (caseInfo.getCaseDataStatus().equals(CaseDataStatus.PAUSE)) {
            throw new BadRequestException(null, "caseInfo", "case.is.stop");
        }
        if (caseInfo.getCaseDataStatus().equals(CaseDataStatus.SETTLT) || caseInfo.getCaseDataStatus().equals(CaseDataStatus.REDUCE)) {
            throw new BadRequestException(null, "caseInfo", "case.is.clear");
        }
        if (!request.getCaseType().equals(caseInfo.getCaseType())) {
            throw new BadRequestException(null, "caseInfo", "case.type.is.change");
        }
        if (caseInfo.getPublicCaseFlag().equals(PublicCaseFlag.PUBLIC_CASE)) {
            throw new BadRequestException(null, "caseInfo", "case.is.public");
        }
        if (Objects.nonNull(request.getAssistId())) {
            AssistCase assistCase = assistCaseRepository.findById(request.getAssistId()).orElseThrow(() -> new BadRequestException(null, "assistCast", "assist.is.null"));
            if (assistCase.getAssistStatus().equals(AssistStatus.ASSIST_COMPLETED) || assistCase.getAssistStatus().equals(AssistStatus.ASSIST_CANCEL)) {
                throw new BadRequestException(null, "assist", "assist.is.cancel");
            }
        }
        UserModel userModel = baseService.getUserByToken(token);
        BaseCase baseCase = baseCaseRespository.findById(request.getCaseId()).orElseThrow(() -> new BadRequestException(null, "caseId", "case.is.null"));
        CaseFollowupRecord caseFollowupRecord = new CaseFollowupRecord();
        caseFollowupRecord.setId(UUID.randomUUID().toString().replaceAll("-", "")); //主键ID
        caseFollowupRecord.setCertificateNo(baseCase.getCertificateNo()); //证件号
        caseFollowupRecord.setCaseId(baseCase.getId()); //案件ID
        caseFollowupRecord.setCaseNumber(baseCase.getCaseNumber()); //案件编号
        caseFollowupRecord.setPersonalName(baseCase.getPersonalName()); //客户名称
        caseFollowupRecord.setPrincipalId(baseCase.getPrincipalId()); //委托方ID
        caseFollowupRecord.setPrincipalName(baseCase.getPrincipalName()); //委托方名称
        caseFollowupRecord.setOutCollector(request.getOutCollector()); //外访员
        caseFollowupRecord.setRelation(request.getTarget()); //联络对象关系
        caseFollowupRecord.setName(request.getTargetName()); //联络对象姓名
        caseFollowupRecord.setCollectionWay(1); //催记方式
        caseFollowupRecord.setType(FollowType.ADDR); //跟进方式
        caseFollowupRecord.setContactResult(request.getContactResult()); //联络结果
        caseFollowupRecord.setFollNextDate(request.getFollNextDate()); //下次跟进日期
        caseFollowupRecord.setAddrType(request.getAddrType()); //地址类型
        caseFollowupRecord.setAddrStatus(request.getAddrStatus()); //地址状态
        caseFollowupRecord.setDetail(request.getDetail()); //详细地址
        caseFollowupRecord.setContent(request.getContent()); //跟进内容
        caseFollowupRecord.setPromiseFlag(request.getPromiseFlag()); //承诺还款标识
        caseFollowupRecord.setPromiseAmt(request.getPromiseAmt()); //承诺还款金额
        caseFollowupRecord.setPromiseDate(request.getPromiseDate()); //承诺还款日期
        caseFollowupRecord.setPayAmount(request.getPayAmount()); //已还款金额
        caseFollowupRecord.setPayDate(request.getPayDate()); //有还款日期
        caseFollowupRecord.setOutCollector(request.getOutCollector()); //外访员
        //凭证
        if (!request.getCertificate().isEmpty()) {
            request.getCertificate().sort((e1, e2) -> e2.getOperateTime().compareTo(e1.getOperateTime()));
            caseFollowupRecord.setCertificate(request.getCertificate());
        }
        //录音
        if (!request.getRecord().isEmpty()) {
            request.getRecord().sort((e1, e2) -> e2.getOperateTime().compareTo(e1.getOperateTime()));
            caseFollowupRecord.setRecord(request.getRecord());
        }
        //视频
        if (!request.getVideo().isEmpty()) {
            request.getVideo().sort((e1, e2) -> e2.getOperateTime().compareTo(e1.getOperateTime()));
            caseFollowupRecord.setVideo(request.getVideo());
        }
        caseFollowupRecord.process(userModel.getId(), userModel.getRealName(), ZWDateUtil.getNowDateTime());
        caseFollowRecordElastic.save(caseFollowupRecord);
        caseInfo.setAddrRecordCount(Objects.isNull(caseInfo.getAddrRecordCount()) ? 1 : caseInfo.getAddrRecordCount() + 1);
        if (StringUtils.isNotBlank(request.getAssistId())) {
            AssistCase assistCase = assistCaseRepository.findById(request.getAssistId()).orElseThrow(() -> new BadRequestException(null, "assistCase", "assist.is.null"));
            assistCase.setLastContactResult(request.getContactResult());
            assistCase.setLastContactDate(ZWDateUtil.getNowDateTime());
            assistCaseRepository.save(assistCase);
        } else {
            caseInfo.setLastContactResult(request.getContactResult());
            caseInfo.setLastContactDate(ZWDateUtil.getNowDateTime());
            caseInfoRepository.save(caseInfo);
        }
        payCheck(request, userModel, baseCase);
    }

    /**
     * @Author xiaqun
     * @Description 检测是否需要添加ptp cp  记录。
     * @Date 2019/11/21 11:18
     **/
    private void payCheck(AppAddFollowRecordRequest request, UserModel userModel, BaseCase baseCase) {
        PaymentCheck paymentCheck;
        if (Objects.nonNull(request.getPromiseAmt()) && Objects.isNull(request.getPayAmount())) {
            Optional<PaymentCheck> paymentCheckOptional = paymentCheckRepository.findOne(QPaymentCheck.paymentCheck.caseId.eq(baseCase.getId())
                    .and(QPaymentCheck.paymentCheck.isBouncedCheck.eq(BaseSelect.NO)).
                            and(QPaymentCheck.paymentCheck.payCheckStatus.eq(PayCheckStatus.PTP)));
            paymentCheck = paymentCheckOptional.orElseGet(PaymentCheck::new);
            paymentCheck.setCaseId(baseCase.getId());
            paymentCheck.setCertificateNo(baseCase.getCertificateNo());
            paymentCheck.setPersonalName(baseCase.getPersonalName());
            paymentCheck.setOperator(userModel.getId());
            paymentCheck.setBatchNumber(baseCase.getBatchNumber());
            paymentCheck.setCaseNumber(baseCase.getCaseNumber());
            paymentCheck.setPrincipalId(baseCase.getPrincipalId());
            paymentCheck.setPrincipalName(baseCase.getPrincipalName());
            paymentCheck.setIsBouncedCheck(BaseSelect.NO);
            paymentCheck.setOperatorDate(ZWDateUtil.getNowDateTime());
            paymentCheck.setApplyName(userModel.getRealName());
            paymentCheck.setApplyDate(ZWDateUtil.getNowDateTime());
            paymentCheck.setIsReply(BaseSelect.NO);
            paymentCheck.setExportState(ExportState.WAIT_EXPORT);
            paymentCheck.setPromiseAmt(request.getPromiseAmt());
            paymentCheck.setPromiseDate(request.getPromiseDate());
            paymentCheck.setPayCheckStatus(PayCheckStatus.PTP);
            paymentCheckRepository.save(paymentCheck);
        } else {
            if (Objects.nonNull(request.getPayAmount())) {
                long count = paymentCheckRepository.count(QPaymentCheck.paymentCheck.caseId.eq(baseCase.getId())
                        .and(QPaymentCheck.paymentCheck.isReply.eq(BaseSelect.NO)).
                                and(QPaymentCheck.paymentCheck.payCheckStatus.eq(PayCheckStatus.CP)));
                if (count == 0) {
                    PaymentCheck cpCheck = new PaymentCheck();
                    cpCheck.setCaseId(baseCase.getId());
                    cpCheck.setCertificateNo(baseCase.getCertificateNo());
                    cpCheck.setPersonalName(baseCase.getPersonalName());
                    cpCheck.setOperator(userModel.getId());
                    cpCheck.setBatchNumber(baseCase.getBatchNumber());
                    cpCheck.setCaseNumber(baseCase.getCaseNumber());
                    cpCheck.setPrincipalId(baseCase.getPrincipalId());
                    cpCheck.setPrincipalName(baseCase.getPrincipalName());
                    cpCheck.setIsBouncedCheck(BaseSelect.NO);
                    cpCheck.setOperatorDate(ZWDateUtil.getNowDateTime());
                    cpCheck.setApplyName(userModel.getRealName());
                    cpCheck.setApplyDate(ZWDateUtil.getNowDateTime());
                    cpCheck.setIsReply(BaseSelect.NO);
                    cpCheck.setApplyId(userModel.getId());
                    cpCheck.setExportState(ExportState.WAIT_EXPORT);
                    cpCheck.setPromiseAmt(request.getPromiseAmt());
                    cpCheck.setPromiseDate(request.getPromiseDate());
                    cpCheck.setHasPaymentAmt(request.getPayAmount());
                    cpCheck.setHasPaymentDate(request.getPayDate());
                    cpCheck.setPayCheckStatus(PayCheckStatus.CP);
                    paymentCheckRepository.save(cpCheck);
                }
            }
        }
    }

    /**
     * 修改头像
     */
    public void modifyPhoto(String url, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        User user = userRepository.findById(userModel.getId()).orElseThrow(() -> new BadRequestException(null, "user", "user.is.null"));
        user.setUrl(url);
        userRepository.save(user);
    }

    /**
     * 查询PTP/CP记录
     */
    public List<PaymentCheck> getAllRecord(String caseId, PayCheckStatus status) {
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(QPaymentCheck.paymentCheck.caseId.eq(caseId).and(QPaymentCheck.paymentCheck.payCheckStatus.eq(status)));
        Iterable<PaymentCheck> iterable = paymentCheckRepository.findAll(builder);
        List<PaymentCheck> list = IterableUtils.toList(iterable);
        list.sort((e1, e2) -> e2.getOperatorDate().compareTo(e1.getOperatorDate()));
        return list;
    }
}
